home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / letters < prev    next >
Encoding:
Text File  |  1992-01-03  |  49.3 KB  |  1,958 lines

  1. Newsgroups: comp.sources.unix
  2. From: lm03_cif@uhura.cc.rochester.edu (Larry Moss)
  3. Subject: v25i090: letters - game to improve typing skills
  4. Sender: sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: lm03_cif@uhura.cc.rochester.edu (Larry Moss)
  8. Posting-Number: Volume 25, Issue 90
  9. Archive-Name: letters
  10.  
  11. Here is "letters", the "Letter Invader" game.  It is pretty cute. It is less
  12. stressful than Tetris, but it might be a good diversion while waiting
  13. for something to compile.
  14.  
  15. Abstract (lifted from the man page):
  16.  
  17.      Letters is based on Letter Invaders which was around in  the
  18.      PC  environment  several years ago.  It in turn was based on
  19.      the popular arcade style game, Space  Invaders.   For  those
  20.      not  familiar  with  Space  Invaders  (please let me know if
  21.      you're one of these people  and  let  me  know  what  planet
  22.      you've been living on :-) the idea is to blast aliens out of
  23.      the sky as they attempt to land on and  "kill"  you.   Since
  24.      this  is  a  game  to  improve typing skills, the aliens are
  25.      words selected randomly from the dictionary.  You blast  the
  26.      aliens out of the sky by typing them correctly.
  27.  
  28.                         Nick
  29.  
  30. #! /bin/sh
  31. # This is a shell archive.  Remove anything before this line, then unpack
  32. # it by saving it into a file and typing "sh file".  To overwrite existing
  33. # files, type "sh file -c".  You can also feed this as standard input via
  34. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  35. # will see the following message at the end:
  36. #        "End of shell archive."
  37. # Contents:  config.h highscore.c kinput.c kinput.h letters.c term.c
  38. #   term.h terms.h usleep.c usleep5.c word.c Makefile letters.man
  39. #   letters.high README
  40. # Wrapped by lm03_cif@troi.cc.rochester.edu on Wed Jan  1 10:40:44 1992
  41. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  42. if test -f 'config.h' -a "${1}" != "-c" ; then 
  43.   echo shar: Will not clobber existing file \"'config.h'\"
  44. else
  45. echo shar: Extracting \"'config.h'\" \(1720 characters\)
  46. sed "s/^X//" >'config.h' <<'END_OF_FILE'
  47. X/*
  48. X * configurable stuff in letters.  Most things here probably shouldn't need
  49. X * to be changed but are here because someone may want to tinker with this
  50. X * stuff to affect the way it performs on different systems.  The stuff
  51. X * most likely to require changes is at the top of the file.
  52. X */
  53. X#ifndef DICTIONARY
  54. X#define DICTIONARY "/usr/dict/words"
  55. X#endif
  56. X
  57. X#ifndef HIGHSCORES
  58. X#define HIGHSCORES "letters.high"
  59. X#endif
  60. X
  61. X/*
  62. X * probably best to leave these so it's the same everywhere.  Otherwise,
  63. X * anyone with an xterminal is likely to get higher scores.
  64. X */
  65. X#ifdef AMIGA
  66. X#define SCREENLENGTH    22
  67. X#else
  68. X#define SCREENLENGTH    23
  69. X#endif
  70. X#define SCREENWIDTH    80
  71. X
  72. X/*
  73. X * initial delay in usecs before words move to the next line
  74. X */
  75. X#define START_DELAY    750000
  76. X
  77. X/*
  78. X * this implements "graduated" (non-linear) decreasing delay times:
  79. X * each level, delay gets reduced by smaller and smaller amounts
  80. X * (eventually, when delay would get below PAUSE, it is simply set to PAUSE)
  81. X *
  82. X * if you change START_DELAY or DELAY_CHANGE, DECEL must be tuned carefully,
  83. X * otherwise DELAY(lev) will drop suddenly to PAUSE at some point
  84. X */
  85. X#define DELAY_CHANGE    60000
  86. X#define DECEL        1200
  87. X#define DELAY(lev)    ( ((lev)*DECEL > DELAY_CHANGE/2) ? PAUSE :\
  88. X              (START_DELAY-(DELAY_CHANGE-(lev)*DECEL)*(lev)) )
  89. X
  90. X/*
  91. X * number of words to be completed before level change
  92. X */
  93. X#define LEVEL_CHANGE    15
  94. X
  95. X/*
  96. X * length of pause before reading keyboard again (in usecs).  There has to
  97. X * be some pause.
  98. X */
  99. X#define PAUSE        10000
  100. X
  101. X/*
  102. X * This is how likely it is that another word will appear on the screen
  103. X * while words are falling.  there isa 1/ADDWORD chance of a new word
  104. X */
  105. X#define ADDWORD        6
  106. X
  107. X/*
  108. X * length of words in bonus round
  109. X */
  110. X#define BONUSLENGTH    10
  111. END_OF_FILE
  112. if test 1720 -ne `wc -c <'config.h'`; then
  113.     echo shar: \"'config.h'\" unpacked with wrong size!
  114. fi
  115. # end of 'config.h'
  116. fi
  117. if test -f 'highscore.c' -a "${1}" != "-c" ; then 
  118.   echo shar: Will not clobber existing file \"'highscore.c'\"
  119. else
  120. echo shar: Extracting \"'highscore.c'\" \(3677 characters\)
  121. sed "s/^X//" >'highscore.c' <<'END_OF_FILE'
  122. X/*
  123. X * read and update high score file for Letter Invaders
  124. X *
  125. X * copyright 1991 by Larry Moss (lm03_cif@uhura.cc.rochester.edu)
  126. X */
  127. X
  128. X#include <stdio.h>
  129. X#ifdef AMIGA
  130. X# include <stdlib.h>
  131. X# include <string.h>
  132. X#else
  133. X# include <pwd.h>
  134. X#endif
  135. X#include <sys/types.h>
  136. X#include <sys/stat.h>
  137. X#include "config.h"
  138. X#include "term.h"
  139. X#include "terms.h"
  140. X#include "kinput.h"
  141. X
  142. Xstruct score_rec {
  143. X    char    name[9];
  144. X    int    level, words, score;
  145. X};
  146. X
  147. Xstatic char highscores[] = HIGHSCORES;
  148. X
  149. Xextern unsigned score, word_count, level;
  150. X
  151. Xstatic struct score_rec high_scores[10];
  152. Xstatic struct stat    s_buf;
  153. Xtime_t    readtime;
  154. X
  155. Xvoid read_scores() {
  156. X    int         i;
  157. X    FILE         *fp;
  158. X
  159. X    /*
  160. X     * get the last modified time so we know later if we have to reread
  161. X     * the scores before saving a new file.
  162. X     */
  163. X    if(stat(highscores, &s_buf) == -1) {
  164. X        fprintf(stderr, "Cannot stat %s: ", highscores);
  165. X        perror("");
  166. X        exit(1);
  167. X    }
  168. X
  169. X    readtime = s_buf.st_mtime;
  170. X
  171. X    if((fp = fopen(highscores, "r")) == NULL) {
  172. X        fprintf(stderr, "Cannot open %s: ", highscores);
  173. X        perror("");
  174. X        exit(1);
  175. X    }
  176. X
  177. X    for(i = 0; i < 10; i++) {
  178. X        fscanf(fp, "%s%d%d%d", high_scores[i].name,
  179. X               &high_scores[i].level, &high_scores[i].words,
  180. X               &high_scores[i].score);
  181. X    }
  182. X
  183. X    fclose(fp);
  184. X}
  185. X
  186. Xint write_scores() {
  187. X    int    i;
  188. X    FILE    *fp;
  189. X
  190. X    /*
  191. X     * check to make sure the high score list has not been modified
  192. X     * since we read it.
  193. X     */
  194. X    if(stat(highscores, &s_buf) == -1) {
  195. X        fprintf(stderr, "Cannot stat %s: ", highscores);
  196. X        perror("");
  197. X        setterm(ORIG);
  198. X        exit(1);
  199. X    }
  200. X
  201. X    if(s_buf.st_mtime > readtime)
  202. X        return -1;
  203. X
  204. X    if((fp = fopen(highscores, "w")) == NULL) {
  205. X        fprintf(stderr, "Cannot write to %s: ", highscores);
  206. X        perror("");
  207. X        setterm(ORIG);
  208. X        exit(1);
  209. X    }
  210. X
  211. X    for(i = 0; i < 10; i++) {
  212. X        fprintf(fp, "%s %d %d %d", high_scores[i].name,
  213. X               high_scores[i].level, high_scores[i].words,
  214. X               high_scores[i].score);
  215. X    }
  216. X
  217. X    fclose(fp);
  218. X}
  219. X
  220. X
  221. X
  222. Xvoid update_scores() {
  223. X    int i, j;
  224. X#ifdef AMIGA
  225. X    char *u;
  226. X#else
  227. X    struct passwd *p;
  228. X#endif
  229. X
  230. X    for(i = 0; i < 10; i++)
  231. X        if(score > high_scores[i].score) {
  232. X            for(j = 10; j > i; j--) {
  233. X                strcpy(high_scores[j].name, high_scores[j-1].name);
  234. X                high_scores[j].words = high_scores[j-1].words;
  235. X                high_scores[j].score = high_scores[j-1].score;
  236. X                high_scores[j].level = high_scores[j-1].level;
  237. X            }
  238. X#ifdef AMIGA
  239. X                        if((u = getenv("USER")) == NULL) {
  240. X                char buffer[128],*p;
  241. X                clrdisp();
  242. X                gotoxy(18, 5);
  243. X                cooked(stdin);
  244. X                fputs("Enter your name (8 char. max, no spaces): ",stdout);
  245. X                fflush(stdout);
  246. X                gets(buffer);
  247. X                if((p=strchr(buffer,' ')))
  248. X                    *p='\0';
  249. X                if(!buffer[0])
  250. X                    strcpy(buffer,"nobody");
  251. X                strncpy(high_scores[i].name, buffer, 8);
  252. X                raw(stdin);
  253. X                        } else
  254. X                                strcpy(high_scores[i].name, u);
  255. X#else
  256. X            if((p = getpwuid(getuid())) == NULL)
  257. X                                strcpy(high_scores[i].name, "nobody");
  258. X            else
  259. X                strcpy(high_scores[i].name, p->pw_name);
  260. X#endif
  261. X            high_scores[i].score = score;
  262. X            high_scores[i].words = word_count;
  263. X            high_scores[i].level = level;
  264. X            if(write_scores() == -1) {
  265. X                read_scores();
  266. X                update_scores();
  267. X            }
  268. X            break;
  269. X        }
  270. X}
  271. X
  272. Xvoid show_scores() {
  273. X    int i;
  274. X
  275. X    clrdisp();
  276. X    gotoxy(18, 5);
  277. X    highlight(1);
  278. X    printf("Top Ten Scores for Letter Invaders");
  279. X    highlight(0);
  280. X    gotoxy(20, 7);
  281. X    underline(1);
  282. X    printf("  name      level words score");
  283. X    underline(0);
  284. X    
  285. X    for(i = 0; i < 10; i++) {
  286. X        gotoxy(18, 8 + i);
  287. X        printf("%3d %-10s%5d%6d%6d", i+1, high_scores[i].name,
  288. X               high_scores[i].level, high_scores[i].words,
  289. X               high_scores[i].score);
  290. X    }
  291. X
  292. X    printf("\n");
  293. X#ifdef AMIGA
  294. X    {
  295. X        char bogus;
  296. X        fputs("\nPress RETURN... ",stdout);
  297. X        fflush(stdout);
  298. X        bogus=getchar();
  299. X    }
  300. X#endif
  301. X}
  302. END_OF_FILE
  303. if test 3677 -ne `wc -c <'highscore.c'`; then
  304.     echo shar: \"'highscore.c'\" unpacked with wrong size!
  305. fi
  306. # end of 'highscore.c'
  307. fi
  308. if test -f 'kinput.c' -a "${1}" != "-c" ; then 
  309.   echo shar: Will not clobber existing file \"'kinput.c'\"
  310. else
  311. echo shar: Extracting \"'kinput.c'\" \(3666 characters\)
  312. sed "s/^X//" >'kinput.c' <<'END_OF_FILE'
  313. X/*
  314. X * do non-blocking keyboard reads
  315. X *
  316. X * copyright 1991 by Larry Moss (lm03_cif@uhura.cc.rochester.edu)
  317. X */
  318. X
  319. X#include <stdio.h>
  320. X#include <signal.h>
  321. X#include <sys/types.h>
  322. X/* I know some systems prefer time.h, but I'm not sure which */
  323. X#include <sys/time.h>
  324. X#ifdef SYSV
  325. X#include <termio.h>
  326. X#else  /* SYSV */
  327. X#include <sgtty.h>
  328. X#endif /* SYSV */
  329. X
  330. X#include "kinput.h"
  331. X#include "terms.h"
  332. X#include "term.h"
  333. X
  334. X#define SCREENLENGTH 24
  335. X
  336. Xextern unsigned int score, word_count, level;
  337. X
  338. Xint key_pressed();
  339. X
  340. Xstatic interrupt();
  341. X
  342. X#ifndef NOJOB
  343. Xstatic pause();
  344. Xstatic cont();
  345. X#endif
  346. X
  347. Xstatic die();
  348. X
  349. X/*
  350. X * This function will return -1 if no key is available, or the key
  351. X * that was pressed by the user.  It is checking stdin, without blocking.
  352. X */
  353. Xint key_pressed()
  354. X{
  355. X#ifdef SYSV
  356. X    int        chars_read;
  357. X    static char    keypressed;
  358. X
  359. X    chars_read = read(0, &keypressed, 1);
  360. X    if (chars_read == 1)
  361. X        return((int)keypressed);
  362. X    return(-1);
  363. X#else /* SYSV */
  364. X    int        mask = 1, chars_read;
  365. X    static char    keypressed;
  366. X    struct timeval    waittime;
  367. X
  368. X    waittime.tv_sec=0;
  369. X    waittime.tv_usec=4;
  370. X    if (select(1, &mask, 0, 0, &waittime)) {
  371. X        chars_read = read(0, &keypressed, 1);
  372. X        if (chars_read == 1)
  373. X            return((int)keypressed);
  374. X    }
  375. X    return(-1);
  376. X#endif /* SYSV */
  377. X}
  378. X
  379. X/*
  380. X * Set the terminal to cbreak mode, turn off echo and prevent special
  381. X * characters from affecting the input.  We will handle EOF and other fun
  382. X * stuff our own way.  Backup copies of the current setup will be kept
  383. X * to insure the terminal gets returned to its initial state.
  384. X */
  385. Xvoid setterm(setting)
  386. Xint setting;
  387. X{
  388. X#ifdef SYSV
  389. X    struct termio    termrec;
  390. X    static struct termio    old_termrec;
  391. X#else  /* SYSV */
  392. X    struct sgttyb    termrec;
  393. X    struct tchars    trec;
  394. X    static struct tchars    old_trec;
  395. X    static struct sgttyb    old_termrec;
  396. X#endif /* SYSV */
  397. X
  398. X    if(setting == NEW) {
  399. X        signal(SIGINT, interrupt);
  400. X        signal(SIGQUIT, die);
  401. X        signal(SIGTERM, die);
  402. X#ifndef NOJOB
  403. X        signal(SIGTSTP, pause);
  404. X        signal(SIGCONT, cont);
  405. X#endif /* NOJOB */
  406. X        
  407. X#ifdef SYSV
  408. X        ioctl(0, TCGETA, &termrec);
  409. X        old_termrec = termrec;
  410. X        termrec.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
  411. X        termrec.c_iflag |= BRKINT;
  412. X        termrec.c_lflag &= ~(ICANON|ECHO);
  413. X        termrec.c_cc[VTIME] = 0;
  414. X        termrec.c_cc[VMIN] = 0;
  415. X        ioctl(0, TCSETAF, &termrec);
  416. X#else /* SYSV */
  417. X        ioctl(0, TIOCGETP, &termrec);
  418. X        old_termrec = termrec;
  419. X        termrec.sg_flags |= CBREAK;
  420. X        termrec.sg_flags &= ~ECHO;
  421. X        ioctl(0, TIOCSETP, &termrec);
  422. X
  423. X        ioctl(0, TIOCGETC, &trec);
  424. X        old_trec = trec;
  425. X        trec.t_eofc = (char) -1;
  426. X        trec.t_quitc = (char) -1;
  427. X        ioctl(0, TIOCSETC, &trec);
  428. X#endif /* SYSV */
  429. X    }
  430. X    else {
  431. X        signal(SIGINT, SIG_DFL);
  432. X        signal(SIGQUIT, SIG_DFL);
  433. X        signal(SIGTERM, SIG_DFL);
  434. X#ifndef NOJOB
  435. X        signal(SIGTSTP, SIG_DFL);
  436. X#endif  /* NOJOB */
  437. X
  438. X#ifdef SYSV
  439. X        ioctl(0, TCSETAF, &old_termrec);
  440. X#else /* SYSV */
  441. X        ioctl(0, TIOCSETP, &old_termrec);
  442. X        ioctl(0, TIOCSETC, &old_trec);
  443. X#endif /* SYSV */
  444. X    }
  445. X}
  446. X
  447. X
  448. X/*
  449. X * Interrupt handlers
  450. X */
  451. X
  452. X#ifndef NOJOB
  453. Xstatic pause(sig)
  454. Xint    sig;
  455. X{
  456. X#ifdef SYSV
  457. X    signal(sig, interrupt);
  458. X#endif /* SYSV */
  459. X    gotoxy(0, SCREENLENGTH);
  460. X    setterm(ORIG);
  461. X    putchar('\n');
  462. X    kill(getpid(), SIGSTOP);
  463. X}
  464. X
  465. Xstatic cont(sig)
  466. Xint    sig;
  467. X{
  468. X#ifdef SYSV
  469. X    signal(sig, interrupt);
  470. X#endif /* SYSV */
  471. X    setterm(NEW);
  472. X    redraw();
  473. X}
  474. X
  475. X#endif /* NOJOB */
  476. X
  477. Xstatic interrupt(sig)
  478. Xint    sig;
  479. X{
  480. X    char    c;
  481. X
  482. X    setterm(ORIG);
  483. X    printf("\n\rare you sure you want to quit? ");
  484. X    if((c = getchar()) == 'y' || c == 'Y') {
  485. X        clrdisp();
  486. X        printf("\n\nfinal: score = %u\twords = %u\t level = %d\n",
  487. X               score, word_count, level);
  488. X        highlight(0);
  489. X        exit(1);
  490. X    } else {
  491. X#ifdef SYSV
  492. X        signal(sig, interrupt);
  493. X#endif /* SYSV */
  494. X        setterm(NEW);
  495. X        redraw();
  496. X    }
  497. X}
  498. X
  499. Xstatic die(sig)
  500. Xint    sig;
  501. X{
  502. X    setterm(ORIG);
  503. X    clrdisp();
  504. X    highlight(0);
  505. X    exit(1);
  506. X}
  507. END_OF_FILE
  508. if test 3666 -ne `wc -c <'kinput.c'`; then
  509.     echo shar: \"'kinput.c'\" unpacked with wrong size!
  510. fi
  511. # end of 'kinput.c'
  512. fi
  513. if test -f 'kinput.h' -a "${1}" != "-c" ; then 
  514.   echo shar: Will not clobber existing file \"'kinput.h'\"
  515. else
  516. echo shar: Extracting \"'kinput.h'\" \(323 characters\)
  517. sed "s/^X//" >'kinput.h' <<'END_OF_FILE'
  518. X/*
  519. X * header file for:
  520. X * kinput.c: Larry Moss (lm03_cif@cc.rochester.edu)
  521. X *        Fall, 1990
  522. X *
  523. X */
  524. X
  525. X#define BACKSPACE    fputs("\b \b", stdout)
  526. X#define DEL        127
  527. X#define WERASE        23
  528. X#define KILL        21
  529. X#define TAB        9
  530. X#define    ESC        27
  531. X#define CTL(c)        (c & 037)
  532. X#define MAXLENGTH    1024
  533. X#define NEW        1
  534. X#define ORIG        0
  535. X
  536. Xvoid setterm();
  537. END_OF_FILE
  538. if test 323 -ne `wc -c <'kinput.h'`; then
  539.     echo shar: \"'kinput.h'\" unpacked with wrong size!
  540. fi
  541. # end of 'kinput.h'
  542. fi
  543. if test -f 'letters.c' -a "${1}" != "-c" ; then 
  544.   echo shar: Will not clobber existing file \"'letters.c'\"
  545. else
  546. echo shar: Extracting \"'letters.c'\" \(12891 characters\)
  547. sed "s/^X//" >'letters.c' <<'END_OF_FILE'
  548. X/*
  549. X * letters.c: A simple game to help improve typing skills.
  550. X *
  551. X * copyright 1991 Larry Moss (lm03_cif@uhura.cc.rochester.edu)
  552. X */
  553. X
  554. X#define CTRL(c)        (c & 037)
  555. X#define TRUE    1
  556. X#define FALSE    0
  557. X
  558. X#include <stdio.h>
  559. X#include <string.h>
  560. X#include <time.h>
  561. X#ifdef AMIGA
  562. X# include <math.h>
  563. X#endif
  564. X#include "config.h"
  565. X#include "kinput.h"
  566. X#include "terms.h"
  567. X#include "term.h"
  568. X
  569. X#if defined(SYSV)
  570. X# define srandom srand48
  571. X# define random lrand48
  572. X#endif
  573. X
  574. Xstruct s_word {
  575. X    struct s_word *nextword;
  576. X    int    posx;
  577. X    int    posy;
  578. X    int    length;
  579. X    int    drop;
  580. X    int    matches;
  581. X    char    word[1];    /* extensible */
  582. X};
  583. X    
  584. Xint  move();
  585. Xvoid putword();
  586. Xint  game();
  587. Xvoid redraw();
  588. Xvoid erase();
  589. Xvoid status();
  590. Xvoid new_level();
  591. Xvoid banner();
  592. Xstruct s_word *newword();
  593. Xstruct s_word *searchstr(), *searchchar();
  594. Xvoid kill_word();
  595. Xint (*ding)();
  596. X
  597. Xchar *malloc();
  598. Xvoid free();
  599. X
  600. X/*
  601. X * There are too many globals for my taste, but I took the easy way out in
  602. X * a few places
  603. X */
  604. Xunsigned int score = 0;
  605. Xunsigned int level = 0;
  606. Xint levels_played = -1;
  607. Xunsigned int word_count = 0;
  608. Xstatic int lives = 2;
  609. Xstatic long delay;
  610. Xstruct s_word    *words, *lastword, *prev_word;
  611. Xint    bonus = FALSE;    /* to determine if we're in a bonus round */
  612. Xint    wpm = 0;
  613. Xint    letters = 0;
  614. X
  615. Xvoid usage(progname)
  616. Xchar *progname;
  617. X{
  618. X    fprintf(stderr, "Usage: %s [-q | -b] [-l#]\n", progname);
  619. X    fprintf(stderr, "       %s [-h]\n", progname);
  620. X    exit(0);
  621. X}
  622. X
  623. Xvoid main(argc, argv)
  624. Xint argc;
  625. Xchar *argv[];
  626. X{
  627. X    char *progname;
  628. X    int    foo;
  629. X
  630. X    /*
  631. X     * make sure the person is on a tty
  632. X     */
  633. X    if(!isatty(0)) {
  634. X        fputs("where are you?\n", stderr);
  635. X        exit(1);
  636. X    }
  637. X
  638. X    /*
  639. X     * this should also really check to make sure it's being played on
  640. X     * the terminal of the person running it.  People around here have
  641. X     * the habit of redirecting random programs to other screens.
  642. X     */
  643. X     if(!isatty(1)) {
  644. X         fputs("This game can only be played on a terminal!\n", stderr);
  645. X         exit(0);
  646. X     }
  647. X     
  648. X    /*
  649. X     * default bell sound
  650. X     */
  651. X    ding = quiet;
  652. X
  653. X    /*
  654. X     * initialize display stuff
  655. X     */
  656. X    init_term();        /* termcap stuff */
  657. X
  658. X    /*
  659. X     * get name of program
  660. X     */
  661. X#ifdef AMIGA
  662. X    if(argc==0) {  /* called from Workbench */
  663. X        progname="letters";
  664. X        argv[1]=NULL;
  665. X    } else
  666. X#endif
  667. X        progname = argv[0];
  668. X
  669. X    /*
  670. X     * check for options
  671. X     */
  672. X    while(*++argv) {
  673. X        if((*argv)[0] == '-') {
  674. X            switch((*argv)[1]) {
  675. X                case 'b':
  676. X                    ding = bell;
  677. X                    break;
  678. X                case 'q':
  679. X                    ding = quiet;
  680. X                    break;
  681. X                case 'h':
  682. X                    read_scores();
  683. X                    show_scores();
  684. X                    exit(0);
  685. X                    break;
  686. X                case 'l':
  687. X                    sscanf(&argv[0][2], "%d", &level);
  688. X                    if(DELAY(level) < PAUSE) {
  689. X                        fprintf(stderr,    "You may not start at level %d\n", level);
  690. X                        exit(0);
  691. X                    }
  692. X                    break;
  693. X                default:
  694. X                    usage(progname);
  695. X            }
  696. X        } else {
  697. X            usage(progname);
  698. X        }
  699. X    }
  700. X    
  701. X    /*
  702. X     * get stuff initialized
  703. X     */
  704. X#ifdef AMIGA
  705. X    fixedwin(argc,progname);
  706. X#endif
  707. X    setterm(NEW);        /* signal stuff, keyboard stuff */
  708. X    srandom(getpid());
  709. X    clrdisp();
  710. X    new_level();
  711. X    status();
  712. X    words = NULL;
  713. X    
  714. X    for(;;) {
  715. X        /*
  716. X         * allocate memory for the first word and then find a word
  717. X         * if there are no others on the screen.  There must always
  718. X         * be at least one word active.
  719. X         */
  720. X        if(words == NULL) {
  721. X            lastword = words = newword((struct s_word *)NULL);
  722. X            prev_word = NULL;
  723. X            putword(lastword);
  724. X        }
  725. X        
  726. X        if(game() == 0) {
  727. X            /*
  728. X             * all finished.  print score and clean up.
  729. X             */
  730. X            gotoxy(0, SCREENLENGTH);
  731. X            fflush(stdout);
  732. X            putchar('\n');
  733. X            break;
  734. X        }
  735. X    }
  736. X
  737. X    read_scores();
  738. X    update_scores();
  739. X    sleep(2);
  740. X    show_scores();
  741. X    printf("\n\nfinal: score = %u\twords = %u\t level = %d\n",
  742. X           score, word_count, level);
  743. X
  744. X    /*
  745. X     * flush keyboard and quit.
  746. X     */
  747. X    while(key_pressed() != -1);
  748. X    setterm(ORIG);
  749. X    exit(0);
  750. X}
  751. X
  752. X/*
  753. X * move all words down 1 or more lines.
  754. X * return the number of words that have fallen off the bottom of the screen
  755. X */
  756. Xint move()
  757. X{
  758. X    struct s_word  *wordp, *next;
  759. X    int        died;
  760. X    
  761. X    died = 0;
  762. X    for(wordp = words; wordp != NULL; wordp = next) {
  763. X        next = wordp->nextword;
  764. X        erase(wordp);
  765. X        wordp->posy += wordp->drop;
  766. X
  767. X        if(wordp->posy >= SCREENLENGTH) {
  768. X            kill_word(wordp);
  769. X            died++;
  770. X        }
  771. X        else {
  772. X            putword(wordp);
  773. X        }
  774. X    }
  775. X    return died;
  776. X}
  777. X
  778. X/*
  779. X * erase a word on the screen by printing the correct number of blanks
  780. X */
  781. Xvoid erase(wordp)
  782. Xstruct s_word *wordp;
  783. X{
  784. X    int    i;
  785. X
  786. X    gotoxy(wordp->posx, wordp->posy);
  787. X    for(i = 0; i < wordp->length; i++)
  788. X        putchar(' ');
  789. X}
  790. X
  791. X/*
  792. X * write the word to the screen with already typed letters highlighted
  793. X */
  794. Xvoid putword(wordp)
  795. Xstruct s_word *wordp;
  796. X{
  797. X    int    i;
  798. X
  799. X    gotoxy(wordp->posx, wordp->posy);
  800. X
  801. X    /*
  802. X     * print the letters in the word that have so far been matched
  803. X     * correctly.
  804. X     */
  805. X    highlight(1);
  806. X    for(i = 0; i < wordp->matches; i++)
  807. X        putchar(wordp->word[i]);
  808. X    highlight(0);
  809. X
  810. X    /*
  811. X     * print the rest of the word.
  812. X     */
  813. X    for(i = wordp->matches; i < wordp->length; i++)
  814. X        putchar(wordp->word[i]);
  815. X}
  816. X
  817. X/*
  818. X * Here's the main routine of the actual game.
  819. X */
  820. Xint game()
  821. X{
  822. X    int        key;
  823. X    unsigned    i;
  824. X    int        died;
  825. X    struct s_word    *curr_word, *temp_word;
  826. X
  827. X    /*
  828. X     * look to see if we already have a partial match, if not
  829. X     * set the current word pointer to the first word
  830. X     */
  831. X    for(curr_word = words; curr_word; curr_word = curr_word->nextword)
  832. X        if (curr_word->matches > 0)
  833. X            break;
  834. X    if (!curr_word)
  835. X        curr_word = words;
  836. X    
  837. X    while(curr_word->matches < curr_word->length) {
  838. X        for(i = 0; i < delay; i+= PAUSE) {
  839. X            while((curr_word->matches != curr_word->length) &&
  840. X                  ((key = key_pressed()) != -1)) {
  841. X                if(key == CTRL('L')) {
  842. X                    redraw();
  843. X                    continue;
  844. X                }
  845. X                if(key == CTRL('N')) {
  846. X                    level++;
  847. X                    delay = DELAY(level);
  848. X                    if(delay < PAUSE)
  849. X                        delay = PAUSE;
  850. X                    status();
  851. X                    continue;
  852. X                }
  853. X                /*
  854. X                 * This stuff deals with collecting letters
  855. X                 * for a word that has already been
  856. X                 * started.  It's kind of clumsy the way
  857. X                 * it's being done now and should be
  858. X                 * cleaned up, but the obvious combination
  859. X                 * of erase() and putword() generate too
  860. X                 * much output to be used at 2400 baud.  (I
  861. X                 * can't play too often at work)
  862. X                 */
  863. X                if(curr_word->matches > 0 &&
  864. X                   key == curr_word->word[curr_word->matches]) {
  865. X                    gotoxy(curr_word->posx + curr_word->matches, curr_word->posy);
  866. X                    highlight(1);
  867. X                    putchar(curr_word->word[curr_word->matches]);
  868. X                    highlight(0);
  869. X                    gotoxy(SCREENWIDTH,SCREENLENGTH);
  870. X                    fflush(stdout);
  871. X                    curr_word->matches++;
  872. X                    /*
  873. X                     * fill the word with characters to
  874. X                     * "explode" it.
  875. X                     */
  876. X                    if(curr_word->matches >= curr_word->length)
  877. X                        for (i = 0; i<curr_word->length; i++)
  878. X                            curr_word->word[i] = '-';
  879. X                    continue;
  880. X
  881. X                } else if(temp_word = searchstr(key,
  882. X                            curr_word->word,
  883. X                            curr_word->matches)) {
  884. X                    erase(temp_word);
  885. X                    temp_word->matches = curr_word->matches;
  886. X                    curr_word->matches = 0;
  887. X                    putword(curr_word);
  888. X                    curr_word = temp_word;
  889. X                    curr_word->matches++;
  890. X                } else if(temp_word = searchchar(key)) {
  891. X                    erase(temp_word);
  892. X                    curr_word->matches = 0;
  893. X                    putword(curr_word);
  894. X                    curr_word = temp_word;
  895. X                    curr_word->matches++;
  896. X                } else {
  897. X                    ding();
  898. X                    curr_word->matches = 0;
  899. X                }
  900. X                erase(curr_word);
  901. X                putword(curr_word);
  902. X                gotoxy(SCREENWIDTH,SCREENLENGTH);
  903. X
  904. X                fflush(stdout);
  905. X            }
  906. X            usleep(PAUSE);
  907. X        }
  908. X
  909. X        died = move();        /* NB: move may invalidate curr_word */
  910. X        if (died > 0)
  911. X        {
  912. X            /*
  913. X             * we only subtract lives if a word reaches the
  914. X             * bottom in a normal round.  If a word reaches
  915. X             * bottom during bonus play, just end the bonus
  916. X             * round.
  917. X             */
  918. X            if(bonus == FALSE)
  919. X                lives -= died;
  920. X            else if(died > 0)
  921. X                new_level();
  922. X                
  923. X            if (lives < 0)
  924. X                lives = 0;
  925. X            status();
  926. X            gotoxy(SCREENWIDTH,SCREENLENGTH);
  927. X            fflush(stdout);
  928. X            return (lives != 0);
  929. X        } else {
  930. X            gotoxy(SCREENWIDTH,SCREENLENGTH);
  931. X            fflush(stdout);
  932. X        }
  933. X        if((random() % ADDWORD) == 0) {
  934. X            lastword = newword(lastword);
  935. X            putword(lastword);
  936. X        }
  937. X    }
  938. X
  939. X    /*
  940. X     * all letters in the word have been correctly typed.
  941. X     */
  942. X
  943. X    /*
  944. X     * erase the word
  945. X     */
  946. X    if(curr_word->length == curr_word->matches) {
  947. X        ding(); ding();
  948. X        erase(curr_word);
  949. X    }
  950. X
  951. X    /*
  952. X     * add on an appropriate score.
  953. X     */
  954. X    score += curr_word->length + (2 * level);
  955. X    letters+= curr_word->length;
  956. X    word_count++;
  957. X    status();
  958. X
  959. X    /*
  960. X     * delete the completed word and revise pointers.
  961. X     */
  962. X    kill_word(curr_word);
  963. X
  964. X    /*
  965. X     * increment the level if it's time.
  966. X     */
  967. X    if(word_count % LEVEL_CHANGE == 0)
  968. X        new_level();
  969. X
  970. X    return 1;
  971. X}
  972. X
  973. X
  974. X/*
  975. X * clear the screen and redraw it
  976. X */
  977. Xvoid redraw() {
  978. X    clrdisp();
  979. X    status();
  980. X    fflush(stdout);
  981. X}
  982. X
  983. X/*
  984. X * display the status line in inverse video
  985. X */
  986. Xvoid status() {
  987. X    static char    line[SCREENWIDTH];
  988. X    int        i;
  989. X
  990. X    sprintf(line, "Score: %-7uLevel: %-3uWords: %-6uLives: %-3dWPM: %-4d",
  991. X        score, level, word_count, lives, wpm);
  992. X
  993. X    /*
  994. X     * fill the line with spaces
  995. X     */
  996. X    for(i = strlen(line); i < SCREENWIDTH - 2; i++)
  997. X        line[i] = ' ';
  998. X
  999. X    highlight(1);
  1000. X    gotoxy(0, SCREENLENGTH);
  1001. X    fputs(line, stdout);
  1002. X    highlight(0);
  1003. X}
  1004. X
  1005. X/*
  1006. X * do stuff to change levels.  This is where special rounds can be stuck in.
  1007. X */
  1008. Xvoid new_level()
  1009. X{
  1010. X    struct s_word    *next, *wordp;
  1011. X    static time_t    last_time = 0L;
  1012. X    time_t        curr_time;
  1013. X
  1014. X    /*
  1015. X     * update the words per minute
  1016. X     */
  1017. X    time(&curr_time);
  1018. X    wpm = (letters / 5) / ((curr_time - last_time) / 60.0);
  1019. X    last_time = curr_time;
  1020. X    letters = 0;
  1021. X
  1022. X    /*
  1023. X     * if we're inside a bonus round we don't need to change anything
  1024. X     * else so just take us out of the bonus round and exit this routine
  1025. X     */
  1026. X    if(bonus == TRUE) {
  1027. X        bonus = FALSE;
  1028. X        banner("Bonus round finished");
  1029. X
  1030. X        /*
  1031. X         * erase all existing words so we can go back to a normal
  1032. X         * round
  1033. X         */
  1034. X        for(wordp = words; wordp != NULL; wordp = next) {
  1035. X            next = wordp->nextword;
  1036. X            kill_word(wordp);
  1037. X        }
  1038. X
  1039. X        status();
  1040. X        return;
  1041. X    }
  1042. X
  1043. X    levels_played++;
  1044. X
  1045. X    /*
  1046. X     * If you start at a level other than 1, the level does not
  1047. X     * actually change until you've completed a number of levels equal
  1048. X     * to the starting level.
  1049. X     */
  1050. X    if(level <= levels_played)
  1051. X        level++;
  1052. X        
  1053. X    delay = DELAY(level);
  1054. X
  1055. X    /*
  1056. X     * no one should ever reach a level where there is no delay, but
  1057. X     * just to be safe ...
  1058. X     */
  1059. X    if(delay < PAUSE)
  1060. X        delay = PAUSE;
  1061. X
  1062. X    if((levels_played % 3 == 0) && (levels_played != 0)) {
  1063. X        bonus = TRUE;
  1064. X
  1065. X        /*
  1066. X         * erase all existing words so we can have a bonus round
  1067. X         */
  1068. X        for(wordp = words; wordp != NULL; wordp = next) {
  1069. X            next = wordp->nextword;
  1070. X            kill_word(wordp);
  1071. X        }
  1072. X
  1073. X        banner("Prepare for bonus words");
  1074. X        lives++;
  1075. X    }
  1076. X    
  1077. X    status();
  1078. X}
  1079. X
  1080. X/*
  1081. X * allocate memory for a new word and get it all set up to use.
  1082. X */
  1083. Xstruct s_word *newword(wordp)
  1084. Xstruct s_word *wordp;
  1085. X{
  1086. X    struct s_word    *nword;
  1087. X    char        *word, *getword(), *bonusword();
  1088. X    int        length;
  1089. X
  1090. X    if(bonus == TRUE)
  1091. X        word = bonusword();
  1092. X    else
  1093. X        word = getword();
  1094. X        
  1095. X    length = strlen(word);
  1096. X
  1097. X    nword = (struct s_word *)malloc(sizeof(struct s_word) + length);
  1098. X    if(nword == (struct s_word *)0) {
  1099. X        perror("\nmalloc");
  1100. X        setterm(ORIG);
  1101. X        exit(1);
  1102. X    }
  1103. X
  1104. X    strncpy(nword->word, word, length);
  1105. X    nword->length = length;
  1106. X    nword->drop = length > 6 ? 1 : length > 3 ? 2 : 3;
  1107. X    nword->matches = 0;
  1108. X    nword->posx = random() % ((SCREENWIDTH - 1) - nword->length);
  1109. X    nword->posy = 0;
  1110. X    nword->nextword = NULL;
  1111. X
  1112. X    if(wordp != NULL)
  1113. X        wordp->nextword = nword;
  1114. X        
  1115. X    return nword;
  1116. X}
  1117. X
  1118. X/*
  1119. X * look at the first characters in each of the words to find one which
  1120. X * one matches the amount of stuff typed so far
  1121. X */
  1122. Xstruct s_word *searchstr(key, str, len)
  1123. Xchar *str;
  1124. Xint  len, key;
  1125. X{
  1126. X    struct s_word    *wordp, *best;
  1127. X
  1128. X    for(best = NULL, prev_word = NULL, wordp = words;
  1129. X        wordp != NULL;
  1130. X        prev_word = wordp,  wordp = wordp->nextword) {
  1131. X        if(wordp->length > len
  1132. X        && strncmp(wordp->word, str, len) == 0
  1133. X        && wordp->word[len] == key
  1134. X        && (!best || best->posy < wordp->posy))
  1135. X            best = wordp;
  1136. X    }
  1137. X
  1138. X    return best;
  1139. X}
  1140. X
  1141. X
  1142. X/*
  1143. X * look at the first character in each of the words to see if any match the
  1144. X * one that was typed.
  1145. X */
  1146. Xstruct s_word *searchchar(key)
  1147. Xchar key;
  1148. X{
  1149. X    struct s_word    *wordp, *best;
  1150. X    
  1151. X    for(best = NULL, prev_word = NULL, wordp = words; wordp != NULL;
  1152. X        prev_word = wordp,  wordp = wordp->nextword) {
  1153. X        if(wordp->word[0] == key
  1154. X         && (!best || best->posy < wordp->posy))
  1155. X            best = wordp;
  1156. X    }
  1157. X
  1158. X    return best;
  1159. X}
  1160. X
  1161. Xvoid kill_word(wordp)
  1162. Xstruct s_word *wordp;
  1163. X{
  1164. X    struct s_word *temp, *prev = NULL;
  1165. X
  1166. X    /*
  1167. X     * check to see if the current word is the first one on our list
  1168. X     */
  1169. X    if(wordp != words)
  1170. X        for(prev = words, temp = words->nextword; temp != wordp;) {
  1171. X            prev = temp;
  1172. X            temp = temp->nextword;
  1173. X        }
  1174. X            
  1175. X    if(prev != NULL) {
  1176. X        prev->nextword = wordp->nextword;
  1177. X    } else
  1178. X        words = wordp->nextword;
  1179. X
  1180. X    if(wordp->nextword != NULL)
  1181. X        wordp->nextword = wordp->nextword->nextword;
  1182. X
  1183. X    if(wordp == lastword)
  1184. X        lastword = prev;
  1185. X
  1186. X    free((char *)wordp);
  1187. X}
  1188. X
  1189. X
  1190. X/*
  1191. X * momentarily display a banner message across the screen and eliminate any
  1192. X * random keystrokes form the last round
  1193. X */
  1194. Xvoid banner(text)
  1195. Xchar *text;
  1196. X{
  1197. X    /*
  1198. X     * display banner message
  1199. X     */
  1200. X    clrdisp();
  1201. X    gotoxy((SCREENWIDTH - strlen(text))/2, 10);
  1202. X    sleep(3);
  1203. X    puts(text);
  1204. X    gotoxy(SCREENWIDTH,SCREENLENGTH);
  1205. X    fflush(stdout);
  1206. X    sleep(2);
  1207. X    clrdisp();
  1208. X
  1209. X    /*
  1210. X     * flush keyboard
  1211. X     */
  1212. X    while(key_pressed() != -1);
  1213. X}
  1214. END_OF_FILE
  1215. if test 12891 -ne `wc -c <'letters.c'`; then
  1216.     echo shar: \"'letters.c'\" unpacked with wrong size!
  1217. fi
  1218. # end of 'letters.c'
  1219. fi
  1220. if test -f 'term.c' -a "${1}" != "-c" ; then 
  1221.   echo shar: Will not clobber existing file \"'term.c'\"
  1222. else
  1223. echo shar: Extracting \"'term.c'\" \(3649 characters\)
  1224. sed "s/^X//" >'term.c' <<'END_OF_FILE'
  1225. X/*
  1226. X * this program will attempt to draw random stuff on the screen by using the
  1227. X * termcap library.  Much of this code was evolved from term.c from the nn
  1228. X * sources.
  1229. X *
  1230. X * Larry Moss (lm03_cif@uhura.cc.rochester.edu)
  1231. X * Kim Storm deserves a fair amount of credit for this.  It may not look
  1232. X *   too much like his code, but his code was at least more understandable
  1233. X *   than the documentation I was trying to work from and I'd like to give
  1234. X *   credit for making it easier for me to write.
  1235. X *
  1236. X * I wrote a fair amount of this based on man pages, then used Kim's code as
  1237. X * a reference to make things work.  Some of this actually ended up looking
  1238. X * more like his code than I planned on.  I hope I haven't gone overboard.
  1239. X */
  1240. X
  1241. X#include <stdio.h>
  1242. X#ifndef NEXT
  1243. X# ifdef AMIGA
  1244. X#  include <stdlib.h>
  1245. X#  include "amitermcap.h"
  1246. X# else
  1247. X#  include <termio.h>
  1248. X# endif
  1249. X#endif
  1250. X#include <string.h>
  1251. X#include "term.h"
  1252. X
  1253. Xchar    *tgoto();
  1254. Xchar    PC, *BC, *UP;
  1255. X
  1256. Xchar        *term_name;
  1257. Xchar    XBC[64], XUP[64];
  1258. Xchar    bell_str[256] = "\007";
  1259. Xchar     cursor_home[64];
  1260. Xchar     clear_screen[64];
  1261. Xchar     cursor_address[128];
  1262. Xchar     enter_standout_mode[64], exit_standout_mode[64];
  1263. Xchar     enter_underline_mode[64], exit_underline_mode[64];
  1264. X
  1265. Xoutc(c)
  1266. X{
  1267. X    putchar(c);
  1268. X}
  1269. X
  1270. Xbell() {
  1271. X    putp(bell_str);
  1272. X}
  1273. X
  1274. Xquiet() {
  1275. X}
  1276. X
  1277. Xint Lines, Columns;    /* screen size */
  1278. Xint garbage_size;    /* number of garbage chars left from so */
  1279. Xint double_garbage;    /* space needed to enter&exit standout mode */
  1280. Xint STANDOUT;        /* terminal got standout mode */
  1281. Xint TWRAP;        /* terminal got automatic margins */
  1282. X
  1283. X/*
  1284. X * used to get the actual terminal control string.
  1285. X */
  1286. Xopt_cap(cap, buf)
  1287. Xchar           *cap, *buf;
  1288. X{
  1289. X    char    *tgetstr();
  1290. X
  1291. X    *buf = '\0';
  1292. X    return tgetstr(cap, &buf) != NULL;
  1293. X}
  1294. X
  1295. X/*
  1296. X * call opt_cap to get control string.  report if the terminal lacks that
  1297. X * capability.
  1298. X */
  1299. Xget_cap(cap, buf)
  1300. Xchar *cap, *buf;
  1301. X{
  1302. X    if (!opt_cap(cap, buf))
  1303. X        fprintf(stderr, "TERMCAP entry for %s has no '%s' capability\n",
  1304. X            term_name, cap);
  1305. X}
  1306. X
  1307. X/*
  1308. X * set everythign up.  find the necessary strings to control the terminal.
  1309. X */
  1310. Xinit_term()
  1311. X{
  1312. X    char            tbuf[1024];
  1313. X
  1314. X#ifndef AMIGA
  1315. X    /*
  1316. X     * get terminal type from the environment or have the user enter it
  1317. X     */
  1318. X    if ((term_name = (char *)getenv("TERM")) == NULL) {
  1319. X        fprintf(stderr, "No TERM variable in environment\n");
  1320. X        fprintf(stderr, "Enter terminal type to use: ");
  1321. X        scanf("%s", term_name = (char *)malloc(30 * sizeof(char)));
  1322. X    }
  1323. X#endif
  1324. X
  1325. X    /*
  1326. X     * get the termcap entry for the terminal above
  1327. X     */
  1328. X    if (tgetent(tbuf, term_name) <= 0) {
  1329. X        fprintf(stderr, "Unknown terminal type: %s\n", term_name);
  1330. X        exit(1);
  1331. X    }
  1332. X
  1333. X    /*
  1334. X     * get the padding character for the terminal
  1335. X     */
  1336. X    opt_cap("pc", cursor_address);    /* temp. usage */
  1337. X    PC = cursor_address[0];
  1338. X
  1339. X    get_cap("cm", cursor_address);
  1340. X    if (!opt_cap("ho", cursor_home))
  1341. X        strcpy(cursor_home, tgoto(cursor_address, 0, 0));
  1342. X
  1343. X    get_cap("cl", clear_screen);
  1344. X
  1345. X    Lines = tgetnum("li");
  1346. X    Columns = tgetnum("co");
  1347. X
  1348. X    opt_cap("so", enter_standout_mode);
  1349. X    opt_cap("se", exit_standout_mode);
  1350. X
  1351. X    opt_cap("us", enter_underline_mode);
  1352. X    opt_cap("ue", exit_underline_mode);
  1353. X
  1354. X    garbage_size = tgetnum("sg");
  1355. X
  1356. X    TWRAP = tgetflag("am");
  1357. X
  1358. X    STANDOUT = HAS_CAP(enter_standout_mode);
  1359. X    if (STANDOUT) {
  1360. X        if (garbage_size < 0)
  1361. X            garbage_size = 0;
  1362. X        double_garbage = 2 * garbage_size;
  1363. X    } else
  1364. X        garbage_size = double_garbage = 0;
  1365. X}
  1366. X
  1367. Xunderline(on)
  1368. X{
  1369. X    if (garbage_size)
  1370. X        return 0;
  1371. X    if (!HAS_CAP(enter_underline_mode))
  1372. X        return 0;
  1373. X    putp(on ? enter_underline_mode : exit_underline_mode);
  1374. X    return 1;
  1375. X}
  1376. X
  1377. Xhighlight(on)
  1378. X{
  1379. X    if (garbage_size)
  1380. X        return 0;
  1381. X    if (!HAS_CAP(enter_standout_mode))
  1382. X        return 0;
  1383. X    putp(on ? enter_standout_mode : exit_standout_mode);
  1384. X    return 1;
  1385. X}
  1386. END_OF_FILE
  1387. if test 3649 -ne `wc -c <'term.c'`; then
  1388.     echo shar: \"'term.c'\" unpacked with wrong size!
  1389. fi
  1390. # end of 'term.c'
  1391. fi
  1392. if test -f 'term.h' -a "${1}" != "-c" ; then 
  1393.   echo shar: Will not clobber existing file \"'term.h'\"
  1394. else
  1395. echo shar: Extracting \"'term.h'\" \(397 characters\)
  1396. sed "s/^X//" >'term.h' <<'END_OF_FILE'
  1397. X/*
  1398. X * header file to be used with term.c.  defines some macros to place the
  1399. X * cursor in various places on the screen.
  1400. X *
  1401. X * Larry Moss (lm03_cif@uhura.cc.rochester.edu)
  1402. X */
  1403. X
  1404. X#define putp(str)    tputs(str, 0, outc)
  1405. X#define HAS_CAP(str)    (*str)
  1406. X#define clrdisp()    tputs(clear_screen, Lines, outc)
  1407. X#define home()        putp(cursor_home)
  1408. X#define gotoxy(c, l)    putp(tgoto(cursor_address, c, l))
  1409. X
  1410. X#define SP ' '
  1411. END_OF_FILE
  1412. if test 397 -ne `wc -c <'term.h'`; then
  1413.     echo shar: \"'term.h'\" unpacked with wrong size!
  1414. fi
  1415. # end of 'term.h'
  1416. fi
  1417. if test -f 'terms.h' -a "${1}" != "-c" ; then 
  1418.   echo shar: Will not clobber existing file \"'terms.h'\"
  1419. else
  1420. echo shar: Extracting \"'terms.h'\" \(723 characters\)
  1421. sed "s/^X//" >'terms.h' <<'END_OF_FILE'
  1422. X/*
  1423. X * header file for term.c
  1424. X */
  1425. X
  1426. Xextern char    *tgoto();
  1427. Xextern char    PC, *BC, *UP;
  1428. X
  1429. Xextern char    *term_name;
  1430. Xextern char    XBC[], XUP[];
  1431. Xextern char    bell_str[];
  1432. Xextern char     *cursor_home;
  1433. Xextern char     clear_screen[];
  1434. Xextern char     cursor_address[];
  1435. Xextern char     enter_standout_mode[], exit_standout_mode[];
  1436. Xextern char     enter_underline_mode[], exit_underline_mode[];
  1437. X
  1438. Xextern outc();
  1439. Xextern bell();
  1440. Xextern quiet();
  1441. X
  1442. Xextern int Lines, Columns;    /* screen size */
  1443. Xextern int garbage_size;    /* number of garbage chars left from so */
  1444. Xextern int double_garbage;    /* space needed to enter&exit standout mode */
  1445. Xextern int STANDOUT;        /* terminal got standout mode */
  1446. Xextern int TWRAP;        /* terminal got automatic margins */
  1447. END_OF_FILE
  1448. if test 723 -ne `wc -c <'terms.h'`; then
  1449.     echo shar: \"'terms.h'\" unpacked with wrong size!
  1450. fi
  1451. # end of 'terms.h'
  1452. fi
  1453. if test -f 'usleep.c' -a "${1}" != "-c" ; then 
  1454.   echo shar: Will not clobber existing file \"'usleep.c'\"
  1455. else
  1456. echo shar: Extracting \"'usleep.c'\" \(615 characters\)
  1457. sed "s/^X//" >'usleep.c' <<'END_OF_FILE'
  1458. X/*
  1459. X * I grabbed this from the FAQ liston comp.unix.questions
  1460. X */
  1461. X/*
  1462. X * usleep -- support routine for 4.2BSD system call emulations
  1463. X * 
  1464. X * last edit:    29-Oct-1984    D A Gwyn
  1465. X */
  1466. X
  1467. Xextern int      select();
  1468. X
  1469. X
  1470. Xint             usleep(usec)    /* returns 0 if ok, else -1 */
  1471. Xlong            usec;        /* delay in microseconds */
  1472. X{
  1473. X    static struct {        /* `timeval' */
  1474. X        long            tv_sec;    /* seconds */
  1475. X        long            tv_usec;    /* microsecs */
  1476. X    }               delay;    /* _select() timeout */
  1477. X
  1478. X    delay.tv_sec = usec / 1000000L;
  1479. X    delay.tv_usec = usec % 1000000L;
  1480. X
  1481. X    return select(0, (long *) 0, (long *) 0, (long *) 0, &delay);
  1482. X}
  1483. END_OF_FILE
  1484. if test 615 -ne `wc -c <'usleep.c'`; then
  1485.     echo shar: \"'usleep.c'\" unpacked with wrong size!
  1486. fi
  1487. # end of 'usleep.c'
  1488. fi
  1489. if test -f 'usleep5.c' -a "${1}" != "-c" ; then 
  1490.   echo shar: Will not clobber existing file \"'usleep5.c'\"
  1491. else
  1492. echo shar: Extracting \"'usleep5.c'\" \(1575 characters\)
  1493. sed "s/^X//" >'usleep5.c' <<'END_OF_FILE'
  1494. X    /*
  1495. X     * subseconds sleeps for System V - or anything that has poll() Don
  1496. X     * Libes, 4/1/1991
  1497. X     * 
  1498. X     * The BSD analog to this function is defined in terms of microseconds
  1499. X     * while poll() is defined in terms of milliseconds.  For
  1500. X     * compatibility, this function provides accuracy "over the long run"
  1501. X     * by truncating actual requests to milliseconds and accumulating
  1502. X     * microseconds across calls with the idea that you are probably
  1503. X     * calling it in a tight loop, and that over the long run, the error
  1504. X     * will even out.
  1505. X     * 
  1506. X     * If you aren't calling it in a tight loop, then you almost certainly
  1507. X     * aren't making microsecond-resolution requests anyway, in which
  1508. X     * case you don't care about microseconds.  And if you did, you
  1509. X     * wouldn't be using UNIX anyway because random system indigestion
  1510. X     * (i.e., scheduling) can make mincemeat out of any timing code.
  1511. X     * 
  1512. X     * Returns 0 if successful timeout, -1 if unsuccessful.
  1513. X     * 
  1514. X     */
  1515. X
  1516. X#include <poll.h>
  1517. X
  1518. X    int
  1519. X                    usleep(usec)
  1520. X    unsigned int    usec;    /* microseconds */
  1521. X    {
  1522. X        static          subtotal = 0;    /* microseconds */
  1523. X        int             msec;    /* milliseconds */
  1524. X
  1525. X        /*
  1526. X         * 'foo' is only here because some versions of 5.3 have a bug
  1527. X         * where the first argument to poll() is checked for a valid
  1528. X         * memory address even if the second argument is 0.
  1529. X         */
  1530. X        struct pollfd   foo;
  1531. X
  1532. X        subtotal += usec;
  1533. X        /* if less then 1 msec request, do nothing but remember it */
  1534. X        if (subtotal < 1000)
  1535. X            return (0);
  1536. X        msec = subtotal / 1000;
  1537. X        subtotal = subtotal % 1000;
  1538. X        return poll(&foo, (unsigned long) 0, msec);
  1539. X    }
  1540. END_OF_FILE
  1541. if test 1575 -ne `wc -c <'usleep5.c'`; then
  1542.     echo shar: \"'usleep5.c'\" unpacked with wrong size!
  1543. fi
  1544. # end of 'usleep5.c'
  1545. fi
  1546. if test -f 'word.c' -a "${1}" != "-c" ; then 
  1547.   echo shar: Will not clobber existing file \"'word.c'\"
  1548. else
  1549. echo shar: Extracting \"'word.c'\" \(1479 characters\)
  1550. sed "s/^X//" >'word.c' <<'END_OF_FILE'
  1551. X/*
  1552. X * find a random word in a dictionary file as part of letters.
  1553. X *
  1554. X * copyright 1991 Larry Moss (lm03_cif@uhura.cc.rochester.edu)
  1555. X */
  1556. X
  1557. X#include <stdio.h>
  1558. X#include <sys/types.h>
  1559. X#include <sys/stat.h>
  1560. X#include "config.h"
  1561. X#include "kinput.h"
  1562. X
  1563. X#ifdef SYSV
  1564. X# define random lrand48
  1565. X#endif
  1566. X
  1567. Xchar *getword()
  1568. X{
  1569. X    static char    buf[512];
  1570. X    static FILE    *fp = NULL;
  1571. X    static struct stat    s_buf;
  1572. X
  1573. X    /*
  1574. X     * This is stuff that only needs to get done once.
  1575. X     */
  1576. X    if(fp == NULL) {
  1577. X        char    *dictionary = DICTIONARY;
  1578. X
  1579. X        /*
  1580. X         * open the dictionary file
  1581. X         */
  1582. X        if((fp = fopen(dictionary, "r")) == NULL) {
  1583. X            fprintf(stderr, "can't open file: %s.\n", dictionary);
  1584. X            setterm(ORIG);
  1585. X            exit(1);
  1586. X        }
  1587. X        
  1588. X        /*
  1589. X         * Get length of dictionary in bytes so we can pick a
  1590. X         * random entry in it.
  1591. X         */
  1592. X        if(stat(dictionary, &s_buf) == -1) {
  1593. X            perror("stat");
  1594. X            setterm(ORIG);
  1595. X            exit(1);
  1596. X        }
  1597. X    }
  1598. X    
  1599. X    /*
  1600. X     * pick a random place in the dictionary
  1601. X     */
  1602. X    fseek(fp, random() % s_buf.st_size, 0);
  1603. X
  1604. X    /*
  1605. X     * read until the end of a line, then read the next word.
  1606. X     */
  1607. X    fscanf(fp, "%*s%s", buf);
  1608. X
  1609. X    /*
  1610. X     * Since we're reading two words at a time it's possible to go past
  1611. X     * the end of the file.  If that happens, use the first word in the
  1612. X     * dictionary.
  1613. X     */
  1614. X    if(buf == NULL) {
  1615. X        fseek(fp, 0L, 0);
  1616. X        fscanf(fp, "%s", buf);
  1617. X    }
  1618. X
  1619. X    return buf;
  1620. X}
  1621. X
  1622. X
  1623. Xchar *bonusword()
  1624. X{
  1625. X    static char    buf[BONUSLENGTH + 1];
  1626. X    int        i;
  1627. X
  1628. X    for(i = 0; i < BONUSLENGTH; i++)
  1629. X        buf[i] = (char)(random() % 94) + 33;
  1630. X
  1631. X    buf[BONUSLENGTH] = 0;
  1632. X
  1633. X    return buf;
  1634. X}
  1635. END_OF_FILE
  1636. if test 1479 -ne `wc -c <'word.c'`; then
  1637.     echo shar: \"'word.c'\" unpacked with wrong size!
  1638. fi
  1639. # end of 'word.c'
  1640. fi
  1641. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  1642.   echo shar: Will not clobber existing file \"'Makefile'\"
  1643. else
  1644. echo shar: Extracting \"'Makefile'\" \(2243 characters\)
  1645. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  1646. X#
  1647. X# Makefile for letters, a game to help improve typing skills
  1648. X#
  1649. X# copyright 1991 by Larry Moss (lm03_cif@uhura.cc.rochester.edu)
  1650. X#
  1651. X
  1652. XCC = cc
  1653. X#CC = gcc
  1654. X#SYSTYPE = SYSV
  1655. X#SYSTYPE = NEXT
  1656. XSYSTYPE = BSD
  1657. X# if you don't have job control add -DNOJOB to CFLAGS
  1658. XCFLAGS = -O -D$(SYSTYPE) -DHIGHSCORES=\"$(LIBDIR)/letters.high\" \
  1659. X    -DDICTIONARY=\"$(DICTIONARY)\"
  1660. XLDFLAGS = -ltermcap
  1661. XBINDIR = $(HOME)/bin-sun4
  1662. XMANDIR = $(HOME)/man/man$(MANEXT)
  1663. XMANEXT = 6
  1664. XLIBDIR = $(HOME)/lib
  1665. XDICTIONARY = /usr/dict/words
  1666. X#DICTIONARY = dictfile
  1667. X
  1668. X# next line only needed if you need to create a dictionary file.  The files
  1669. X# in this directory will be used to make a wordlist.
  1670. XDOCDIR = $(HOME)/man
  1671. X
  1672. X# If your machine doesn't have usleep uncomment it in the following line.
  1673. X# I know this includes ultrix 4.2 and hp-ux 7.? and many sys V based machines.
  1674. X# Don't know about others. if you need usleep and your machine does not have
  1675. X# select, change usleep.o to usleep5.o (mostly sysV machines).
  1676. XOBJS = letters.o kinput.o term.o word.o highscore.o # usleep.o
  1677. X
  1678. X# The following line will stop gcc from complaining about the arguments
  1679. X# sun's make uses.  It shouldn't bother anyone else.
  1680. X.c.o:
  1681. X    $(CC) $(CFLAGS) -c $<
  1682. X
  1683. Xletters: $(OBJS)
  1684. X    $(CC) $(CFLAGS) $(OBJS) -o letters $(LDFLAGS)
  1685. X
  1686. Xletters.o word.o kinput.o: \
  1687. X        kinput.h
  1688. Xletters.o term.o highscore.o kinput.o: \
  1689. X        term.h
  1690. Xletters.o highscore.o kinput.o: \
  1691. X        terms.h
  1692. Xword.o highscore.o letters.o: \
  1693. X        config.h
  1694. X
  1695. Xinstall: letters
  1696. X    install -s -m 2755 letters $(BINDIR)
  1697. X    sed -e 's;LIBDIR;$(LIBDIR);' -e 's;DICTIONARY;$(DICTIONARY);'\
  1698. X        letters.man > letters.$(MANEXT)
  1699. X    install -c -m 0644 letters.$(MANEXT) $(MANDIR)/letters.$(MANEXT)
  1700. X    if [ ! -f $(LIBDIR)/letters.high ] ;then \
  1701. X        install -c -m 0664 letters.high $(LIBDIR) ;fi
  1702. X
  1703. Xinstall_hpux: letters
  1704. X    install -c $(BINDIR) letters
  1705. X    install -c $(MANDIR) letters.man
  1706. X    install -c $(LIBDIR) letters.high
  1707. X    chmod 0666 $(LIBDIR)/letters.high
  1708. X
  1709. Xclean:
  1710. X    rm -f rm *.o letters letters.$(MANEXT)
  1711. X
  1712. Xshar:
  1713. X    shar -o letters.shar *.[ch] Makefile letters.man letters.high README
  1714. X
  1715. Xtar:
  1716. X    tar cf letters.tar *.[ch] Makefile letters.man letters.high README
  1717. X
  1718. Xdict:
  1719. X    awk '{ for (i = 0; i <= NF; ++i)\
  1720. X        if($$i ~ /^[a-zA-Z][a-z]*$$/) { print $$i } }'\
  1721. X        `find $(DOCDIR) -type f -print` |\
  1722. X        sort -u > $(DICTIONARY)
  1723. END_OF_FILE
  1724. if test 2243 -ne `wc -c <'Makefile'`; then
  1725.     echo shar: \"'Makefile'\" unpacked with wrong size!
  1726. fi
  1727. # end of 'Makefile'
  1728. fi
  1729. if test -f 'letters.man' -a "${1}" != "-c" ; then 
  1730.   echo shar: Will not clobber existing file \"'letters.man'\"
  1731. else
  1732. echo shar: Extracting \"'letters.man'\" \(4572 characters\)
  1733. sed "s/^X//" >'letters.man' <<'END_OF_FILE'
  1734. X.TH LETTERS 6 "23 SEPT 1991"
  1735. X.SH NAME
  1736. Xletters \- a game to improve typing skills
  1737. X.SH SYNOPSIS
  1738. X\fBletters\fP [-q | -b] [-l#]
  1739. X.br
  1740. X\fBletters\fP [-h]
  1741. X.SH DESCRIPTION
  1742. X\fBLetters\fP is based on \fBLetter Invaders\fP which was around in the PC
  1743. Xenvironment several years ago.  It in turn was based on the popular
  1744. Xarcade style game, \fBSpace Invaders\fP.  For those not familiar with
  1745. X\fBSpace Invaders\fP \ (please let me know if you're one of these people
  1746. Xand let me know what planet you've been living on :-) the idea is to blast
  1747. Xaliens out of the sky as they attempt to land on and "kill" you.  Since
  1748. Xthis is a game to improve typing skills, the aliens are words selected
  1749. Xrandomly from the dictionary.  You blast the aliens out of the sky by
  1750. Xtyping them correctly.
  1751. X.PP
  1752. XPlaying the game is very straight forward.  Type words as they appear on
  1753. Xthe screen.  They will slowly drop until you have either typed them
  1754. Xcorrectly or they reach the status line on the bottom of the screen.  If
  1755. Xa word makes it to the bottom of the screen you lose one "life".  This is
  1756. Xactually a non-violent game.  The words "kill" and "life" are only used
  1757. Xin this context for historical reasons.
  1758. X.PP
  1759. XIf at any point you type a letter incorrectly the entire word is reset.
  1760. XThe backspace key will not save you if you're a sloppy typist.  
  1761. XIt is not necessary to type words in the order they appear on the
  1762. Xscreen.  In fact, that is often not the
  1763. Xbest action to take.  Very short words fall faster than longer ones.
  1764. XThe program will attempt to determine the word you are
  1765. Xtrying to type by matching what you've typed with the first letter(s) of
  1766. Xall other words on the screen.  Unlike in previous versions the program
  1767. Xtries to determine what word you are typing by more than the first
  1768. Xletter.  The highlight bar doesn't move to a new word until it is clear
  1769. Xwhich word is being typed.
  1770. X.PP
  1771. XIf you successfully complete 3 rounds of play you get a bonus life and
  1772. Xyou get the opportunity to play a bonus round.  The bonus round is played
  1773. Xthe same as all other rounds but the words are strings of random
  1774. Xprintable characters.  The round is played at the same speed as whatever
  1775. Xlevel you were on and likewise points are computed the same as in that
  1776. Xround. since this is just a bonus round, you can only gain points.  You
  1777. Xcannot die.  The round lasts as long as all other rounds (15 words)
  1778. Xunless a word reaches the bottom of the screen.
  1779. X.SH "Special Keys"
  1780. X.IP
  1781. Xctrl-L    Redraw screen.
  1782. X.IP
  1783. Xctrl-C    Exit from the game.  You will be prompted before exiting to make
  1784. Xsure that's really what you wanted to do.  Since it prompts you this can
  1785. Xalso be used as a method of pausing the game.  This is actually whatever
  1786. Xyour interrupt character is.  Ctrl-C is just most common.
  1787. X.IP
  1788. Xctrl-N    Skip to next level.  The game does correctly keep track of how
  1789. Xmany levels you have completed.  (See '-l' under \fBOPTIONS\fP)
  1790. X.IP
  1791. Xctrl-Z    Works as it should.  If your system has job control it will stop
  1792. Xthe process.
  1793. X.SH OPTIONS
  1794. X.IP
  1795. X-q    quiet mode (default) - turn off the obnoxious beep
  1796. X.IP
  1797. X-h    Show high scores.
  1798. X.IP
  1799. X-b    Beep when words are completed or mistyped.
  1800. X.IP
  1801. X-l#    # is the level number that you want to start at.  The level will
  1802. Xnot increase until you have completed the number of rounds equal to your
  1803. Xstarting level.  In other words, if you start on level 5, you need to
  1804. Xplay through 5 rounds before the level increases to 6 (and the speed
  1805. Xincreases and scoring changes).
  1806. X.SH SCORING
  1807. XA word's point value = (# of letters) + 2 * (current level).  No points
  1808. Xare added for partially typed words.
  1809. X.SH "STATUS LINE"
  1810. XIt's fairly obvious what most of the things on the status line are.  The
  1811. Xlast thing on the line however is words per minute.  This is computed at
  1812. Xthe end of each round based on 5 letter words.  It's not a particularly
  1813. Xaccurate measure of your typing speed, but I think it's an interesting
  1814. Xenough statistic to justify filling up the empty space on the status line.
  1815. X.SH FILES
  1816. XDICTIONARY
  1817. X.br
  1818. XLIBDIR/letters.high
  1819. X.SH BUGS
  1820. X"Transmogrifier" doesn't appear frequently.
  1821. X.SH AUTHORS
  1822. XLarry Moss (lm03_cif@uhura.cc.rochester.edu) - original game, UNIX version
  1823. X.br
  1824. XBrent Nordquist (brent@limabean.veggard.mn.org) - amiga version, also
  1825. Xfixed some of bugs.
  1826. X.SH THANKS
  1827. XChris Uppal (chrisu@sco.com) for contributing enormously to the
  1828. Xprogram with a couple of bug fixes, variable speed words, some
  1829. Xperformance improvements, SYSV compatibility, and many suggestions.
  1830. X.sp
  1831. XMark Levinson (mrle_cif@uhura.cc.rochester.edu) for pointing out the bug
  1832. Xlisted above.
  1833. X.sp
  1834. XThanks also to everyone else that's sent me mail with comments and/or
  1835. Xsuggestions.
  1836. END_OF_FILE
  1837. if test 4572 -ne `wc -c <'letters.man'`; then
  1838.     echo shar: \"'letters.man'\" unpacked with wrong size!
  1839. fi
  1840. # end of 'letters.man'
  1841. fi
  1842. if test -f 'letters.high' -a "${1}" != "-c" ; then 
  1843.   echo shar: Will not clobber existing file \"'letters.high'\"
  1844. else
  1845. echo shar: Extracting \"'letters.high'\" \(175 characters\)
  1846. sed "s/^X//" >'letters.high' <<'END_OF_FILE'
  1847. Xhfir_cif 9 121 871hfir_cif 8 115 850hfir_cif 8 106 818hfir_cif 8 113 803lm03_cif 6 82 633lm03_cif 6 85 611jcm8_cif 6 78 557jcm8_cif 5 74 522jcm8_cif 4 47 366jcm8_cif 4 47 352
  1848. END_OF_FILE
  1849. if test 175 -ne `wc -c <'letters.high'`; then
  1850.     echo shar: \"'letters.high'\" unpacked with wrong size!
  1851. fi
  1852. # end of 'letters.high'
  1853. fi
  1854. if test -f 'README' -a "${1}" != "-c" ; then 
  1855.   echo shar: Will not clobber existing file \"'README'\"
  1856. else
  1857. echo shar: Extracting \"'README'\" \(3963 characters\)
  1858. sed "s/^X//" >'README' <<'END_OF_FILE'
  1859. XLetter Invaders v2.1
  1860. XA game to help improve typing skills.
  1861. X=====================================
  1862. X
  1863. XCopying:
  1864. X
  1865. XPlease put this on as many different machines as you like.  If you make
  1866. Xchanges or bug fixes, please mail them to me so they can be incorporated
  1867. Xinto later versions.  Feel free to use the entire program or portions of
  1868. Xit in any way you like as long as I get credit for what I've done.
  1869. X
  1870. X
  1871. XInstallation:
  1872. X
  1873. XInstallation of letters should be fairly simple.  A few lines in the
  1874. XMakefile should be changed to reflect the directories where the files
  1875. Xshould be installed.  Config.h may (but shouldn't) require a couple of
  1876. Xchanges.  After making the minor changes, "make install" or "make
  1877. Xinstall_hpux" should do all the work.  The hpux installation could be
  1878. Ximproved, but it is enough to get it up and running.  If your system does
  1879. Xnot have /usr/dict/words or any other large collection of words you can
  1880. Xuse "make dict" to create a wordlist.  Well, it works for me, but I use
  1881. Xawk to do it so I know someone is bound to have a problem.
  1882. X
  1883. XSo far it has been compiled and run under SunOS 4.0 and 4.1.1, SCO Xenix,
  1884. XULTRIX 4.2, hpux 7.05, and NeXT (mach, I guess) and a large number of
  1885. Xothers.  When compiling it on the NeXT it produces a number of warnings
  1886. Xbut there are no serious problems (I'd fix it, but my access to a NeXT is
  1887. Xfairly limited so I just made sure it compiles).  Please let me know
  1888. Xabout any other platforms that it gets compiled on or fails to get
  1889. Xcompiled on.
  1890. X
  1891. XThe game has been ported to the amiga.  A large portion of the code
  1892. Xnecessary to make it compile on the amiga is not included with the UNIX
  1893. Xdistribution.  All UNIX specific and Amiga specific stuff has been kept
  1894. Xseparate so that it will be easy to keep versions the same if/when the
  1895. Xgame is improved.
  1896. X
  1897. XI'd like to mention that there is a minix version of the game available.
  1898. XThe changes to make it compile under minix are not included in this
  1899. Xpackage (although there have been enough changes to accomodate other
  1900. Xsystems that it might not be too much work any more to get it to compile
  1901. Xon minix).  Credit for the minix version (and comments and questions) to
  1902. XWim van Dorst (baron@wiesje.hobby.nl).  I've been told the minix version
  1903. Xcan be foundon your favorite minix archive site.
  1904. X
  1905. Xauthors
  1906. X-------
  1907. XLarry Moss (lm03_cif@uhura.cc.rochester.edu) - original game, UNIX version
  1908. XBrent J. Nordquist (brent@limabean.veggard.mn.org) - amiga version
  1909. X
  1910. X
  1911. XThanks to:  
  1912. X----------
  1913. X
  1914. XD. A. Gwyn.  I have used his code for usleep() to get it to compile on
  1915. Xmachines that don't have it.  Since the code is included in the FAQ
  1916. Xposted to comp.unix.questions I assume this is ok.  If someone knows
  1917. Xotherwise please let me know.
  1918. X
  1919. XKim Storm.  I used his nn code as a reference when trying to figure out
  1920. Xhow to use the termcap library.
  1921. X
  1922. XChris Uppal (chrisu@sco.com).  He has contributed enormously to the
  1923. Xprogram with a couple of bug fixes, variable speed words, some
  1924. Xperformance improvements, SYSV compatibility, and many suggestions.
  1925. X
  1926. XWim van Dorst (baron@wiesje.hobby.nl).  Creator of the minix version of
  1927. Xthe game.
  1928. X
  1929. X
  1930. X
  1931. XFuture plans:
  1932. X
  1933. XI had at one time planned to have bonus words fly horizontally across
  1934. Xscreen, but I never bothered with implementing it.  Instead, I just got a
  1935. Xsuggestion to have the bonus words come down like the others, but
  1936. Xunderlined.  When a bonus word is typed correctly it will take out the
  1937. Xwhole screen with it.  This could add a bit of strategy to the game.
  1938. X
  1939. Xinteresting things should happen at higher levels.  Now it just keeps
  1940. Xgetting faster.  I've gotten the suggestion of possibly having some words
  1941. Xon the screen change randomly to force you to watch the screen more
  1942. Xcarefully.
  1943. X
  1944. XI've considered using this as an excuse to learn X programming.  I figure
  1945. Xthat way words can really explode.  This will only happen if I find
  1946. Xmyself with a lot of free time.
  1947. X
  1948. XFrequently mistyped words should come back later in the game.  This would
  1949. Xcertainly make the game more useful as a typing tutor.
  1950. END_OF_FILE
  1951. if test 3963 -ne `wc -c <'README'`; then
  1952.     echo shar: \"'README'\" unpacked with wrong size!
  1953. fi
  1954. # end of 'README'
  1955. fi
  1956. echo shar: End of shell archive.
  1957. exit 0
  1958.